from sys import argv
import hashlib
import os
from flask import Flask,request
from flask.helpers import send_file, send_from_directory, stream_with_context
from flask.wrappers import Response
import time 
app = Flask(__name__)


class MPath():
    def __init__(self,code,path:str,isdir) -> None:
        self.path = path 
        self.code =code
        self.isdir = isdir
        self.name = os.path.basename(path)
IGNORE_PATH = ['jkplayer','run.bat','server.py']
class Pool():
    VDICT = {} #code 2 Mpath
    root = None #path of media root
    def __init__(self,path_root) -> None:
        self.root = path_root
        self.build_VDICT()

    def build_VDICT(self):
        for d in os.listdir(self.root):
            r_path = os.path.join(self.root,d)
            if os.path.isdir(r_path) and d not in IGNORE_PATH:
                code =  hashlib.md5(r_path.encode()).hexdigest()
                self.VDICT[code] = MPath(code,r_path,True)
                for root, dirs, files in os.walk(os.path.join(self.root,d), topdown=False):
                    for name in files:
                        fp = os.path.join(root, name)
                        code =  hashlib.md5(fp.encode()).hexdigest()
                        self.VDICT[code] = MPath(code,fp,False)
                    for name in dirs:
                        fp = os.path.join(root, name)
                        code =  hashlib.md5(fp.encode()).hexdigest()
                        self.VDICT[code] = MPath(code,fp,True)
            elif os.path.isfile(r_path):
                code =  hashlib.md5(r_path.encode()).hexdigest()
                self.VDICT[code] = MPath(code,r_path,False)
    def get_mpath(self,key):
        if key in self.VDICT:
            return self.VDICT[key]
        else:
            return None
    def path_decode(self,key):
        '''
        返回None ,Mpath ,list of Mpath or None
        '''
        if key in self.VDICT:
            mpath = self.VDICT[key]
        else:
            return None
        if mpath.isdir:
            ret = list()
            for d in os.listdir(mpath.path):
                fp = os.path.join(mpath.path, d)
                key = hashlib.md5(fp.encode()).hexdigest()
                if key not in self.VDICT:
                    continue
                ret.append(self.get_mpath(key))
            return ret
        else:
            return mpath
    def root_list(self):
        ret = list()
        for d in os.listdir(self.root) :
                fp = os.path.join(self.root, d)
                key = hashlib.md5(fp.encode()).hexdigest()
                if key not in self.VDICT:
                    continue
                ret.append(self.get_mpath(key))
        return ret
pool = None 
def list_page_gen(mpList):
    l = []
    for mp in mpList:
        if mp.isdir:
            l.append(f"<li><a  href={'/list/'+mp.code}>{mp.name}</a></li>")
        else:
            l.append(f"<li><a target='_blank' href={'/play/'+mp.code}>{mp.name}</a></li>")
    body= f'''
            <html>
            <body id="pa">
            <ul>{"<BR/>".join(l)}</ul>
            <body>

            </html>
        '''
    return body
@app.errorhandler(404)
def error404(err):
    return '404 error, nothing here, sorry!'
@app.route('/list/<key>')
def _list(key):
    '''
    只允许目录访问这个link
    '''
    return  list_page_gen(pool.path_decode(key))

@app.route('/')
def index():
   return list_page_gen( pool.root_list())

@app.route("/play/<key>")
def play(key):
    body= f'''
    <html>
    <body >
    <video width="640"  controls autoplay src="/media/{key}" preload="none" >
    
    
    您的浏览器不支持 video 标签。
    </video>

    <body>
    <script>

    </script>
    </html>'''
    return body
def stream_return(file,chunk=1024):
    yded = 0
    fsize  = os.path.getsize(file)
    #chunk=1024*1024
    with open(file,'rb') as f:
        c = f.read()
    while True:
        remaining = fsize-yded
        if yded>=fsize:
            break
        if remaining>=chunk:
            yield yded,chunk,fsize,c[yded:yded+chunk]
        else:
            yield yded,chunk,fsize,c[yded:-1]
        yded+=chunk
        


@app.route("/media/<key>")
def media(key):
    mp = pool.get_mpath(key)
    if mp:
        # return app.send_static_file(os.path.join("./",mp.path))
        #return send_file(os.path.join("./",mp.path),"video/*")
        pt = os.path.join("./",mp.path)
        return send_from_directory(os.path.dirname(pt),os.path.basename(pt))
        # return stream_return(os.path.join("./",mp.path))
        range_header = request.headers.get('Range', None)
        yded,chunk,fsize,c=stream_return(os.path.join("./",mp.path))
        if range_header:
            resp = Response(
                c,
                status=206,
                mimetype='video/mp4',
                content_type='video/mp4',
                direct_passthrough=True

            )
            resp.headers.add('Content-Range',
                            'bytes {0}-{1}/{2}'
                            .format(yded,
                                    chunk,
                                    fsize))
            return resp
        return Response(
            c,
            status=200, mimetype='video/mp4'
        )        
    # resp.headers['X-Accel-Buffering'] = 'no'
    #     resp.headers['Content-Length'] = 1024
    #     resp.headers['Content-Type'] = 'video/*'

        return resp
    return error404()

if __name__ == "__main__":
    default_port = 5005
    pool = Pool("./")
    if len(argv)==2:
        default_port = argv[1]
    app.run("0.0.0.0",default_port)

